import copy
import random

# The side length of the square board:
SIDE = 32

# The board is represented by a list with CELL_CNT count:
CELL_CNT = SIDE * SIDE

# The number of randomly generated ants:
ANT_CNT = 1 #50

# The number of randomly generated morsels:
MORSEL_CNT = SIDE * 3 #89

# Read-only structure to facilitate 2D moving of objects in a list:
DIRECTION = (('A', -SIDE, 0), ('>', 1, 90), ('V', SIDE, 180), ('<', -1, 270))

class BoardPosition(object):
    def __init__(self, ID, board):
        self.ID = ID
        self.board = board
      
class Ant(BoardPosition):
    """ Represents ants
    """
    def __init__(self, ID, board, direction):
        """ Contructor """
        BoardPosition.__init__(self, ID, board)
        self.direction = direction

    def __eq__(self, other):
        return self.ID == other.ID
    
    def __str__(self):
        return self.direction[0][0]
        
    def __repr__(self):
        return self.__str__()

    def do_something(self, do_func):
        """ This will perfrom the given function on the ant.
        """
        do_func(self)

    def advance(self):
        """ Moves ahead.
        If a morsel is ahead, replaces it with an empty cell.
        """
        idx = self.board.board.index(self)
        direction = self.direction[0][1]
        idx_ahead = idx + direction
        if idx_ahead > -1 and idx_ahead < len(self.board.board) and distance(coord(idx), coord(idx_ahead)) == 1:
            self.board.board[idx], self.board.board[idx_ahead] = self.board.board[idx_ahead], self.board.board[idx]
            if type(self.board.board[idx]) == Morsel:
                   self.board.board[idx] = Empty(self.board.board[idx].ID, self.board)

    def turn_right(self):
        """ Turns right
        """
        self.direction = rotate_right(self.direction)

    def turn_left(self):
        """ Turns left
        """
        self.direction = rotate_left(self.direction)

    def is_morsel_ahead(self):
        idx = self.board.board.index(self)
        direction = self.direction[0][1]
        idx_ahead = idx + direction
        if idx_ahead > -1 and idx_ahead < len(self.board.board):
            if type(self.board.board[idx_ahead]) == Morsel:
                return True
        return False

class Morsel(BoardPosition):
    def __eq__(self, other):
        return self.ID == other.ID
       
    def __str__(self):
        return 'o'
    
    def __repr__(self):
        return self.__str__()
    

class Empty(BoardPosition):
    def __eq__(self, other):
        return self.ID == other.ID
    
    def __str__(self):
        return '-'
    
    def __repr__(self):
        return self.__str__()

class AntGameBoard:
    """ A class to reprecent a single ant game.
    """
    def __init__(self, seed = random.randrange(1000)):
        """ Creates a number of uniformly distributed and ants and morsels on the game board.
        Will be changed to allow ants to come out of a nest.
        """
        ant_positions = [0 for i in range(ANT_CNT)]
        random.seed(seed)
        morsel_positions = [random.randrange(CELL_CNT) for i in range(MORSEL_CNT)]
        self.board = []
        for i in range(CELL_CNT):
            if i in ant_positions:
                self.board.append(Ant(i, self, random_direction()))
            elif i in morsel_positions:
                self.board.append(Morsel(i, self))
            else:
                self.board.append(Empty(i, self))
                
    def __str__(self):
        """ Returns a 2-dimensional string representation of the list used as a board
        """
        r = ''
        for i in range(SIDE):
            for j in range(SIDE):
                r += self.board[i * SIDE + j].__str__() + ' '
            r += '\n'                   
        return r
    
    def __repr__(self):
        return self.__str__()
        
    def ants_in(self):
        """ Returns a list of all the ants in the given board.
        """
        return [cell for cell in self.board if type(cell) == Ant]
    
    def morsels_in(self):
        """ Returns a list of all the morsels that are left on the given board.
        """
        return [morsel for morsel in self.board if type(morsel) == Morsel]
        
    def peform_chromosome(self, chromosome_function):
        """ Peforms the given chromosome on the board. Returns
        true if the given board has no more Morsels.
        """
        for ant in ants_in(self.board):         # For each ant
            chromosome_function(ant)
            
            # Check if complete
            if len(self.morsels_in()) == 0:
                return True
        return False

## HELPER FUNCTIONS
def rotate_right(direction):
    """ Rotates a direction list (ex. up becomes right)
    """
    return direction[1:] + [direction[0]]


def rotate_left(direction):
    """ Rotates a direction list (ex. up becomes left)
    """
    return [direction[-1]] + direction[0:-1]


def random_direction():
    """ Randomly rotates the immutable default direction DIRECTION to create random directions
    """
    direction = list(DIRECTION)
    for i in range(random.randrange(len(DIRECTION))):
        direction = rotate_right(direction)
    return direction

def coord(idx):
    """ Returns the coordinates of the indexed object
    """
    return idx % SIDE, idx / SIDE

def distance(coord1, coord2):
    """ Distance between two coordinates
    """
    diff = []
    for i in range(len(coord1)):
        diff.append(abs(coord1[i] - coord2[i]))
    return sum(diff)
    
current_seed = None
current_board = None
def get_board(seed = random.randrange(1000)):
    """ Returns a board, a new board does not need to be created, only copied
    if a board with the given seed was created last.
    """
    global current_board
    global current_seed
    if current_seed != seed:
        if current_board == None:
            current_board = AntGameBoard(seed)
    else:
        current_seed = seed
        current_boad = AntGameBoard(seed)
    return copy.deepcopy(current_board)

# Make work with old stuff
temp_ag = AntGameBoard()

def init_board(seed = random.randrange(1000)):
    temp_ag = AntGameBoard(seed)
    return temp_ag.board

def pretty_board(board):
    temp_ag.board = board
    print temp_ag
    
def ants_in(board):
    temp_ag.board = board
    return temp_ag.ants_in()
    
def morsels_in(board):
    temp_ag.board = board
    return temp_ag.morsels_in()
    
def peform_chromosome(board, chromosome_function):
    temp_ag.board = board
    return temp_ag.peform_chromosome(chromosome_function)
